#pragma once

#ifndef LHJ_CORE_SERVICE_LORA_SERVICE_H__
#define LHJ_CORE_SERVICE_LORA_SERVICE_H__

#include "service.h"
#include <thread>
#include <mutex>
#include <functional>
#include <publisher.h>
#include <map>
#include <memory>
#include <model.h>
#include <serialport.h>
#include <condition_variable>
#include <chrono>

namespace cores
{
    namespace services
    {
        /**
         * @brief 第一个版本传输器的Lora服务
         */
        namespace v1
        {
            using namespace std;
            using namespace cores::topics;
            using namespace cores::datas::models::terminal;
            using namespace cores::devices;

            /**
             * @brief Class LoraStatus的作用
             *          1、检查Lora状态，当Lora设备不在线时间过长时，要告警
             *          2、生成检查Lora在线状态的协议流
             */
            class LoraStatus
            {
            private:
                /**
                 * @brief LoraID
                 */
                uint16_t _loraId;

                /**
                 * @brief 上次更新时间
                 */
                chrono::steady_clock::time_point _updateTime;

                /**
                 * @brief 过期时间
                 */
                uint32_t _expireTime;

                /**
                 * @brief 配置错误
                 */
                bool _configIsOk{false};

                /**
                 * @brief 需要下载到Lora设备
                 */
                bool _neededDownToLora{false};

            public:
                /**
                 * @brief   构造函数
                 *          expireTime 以秒为单位
                 */
                LoraStatus(const uint16_t &loraId, const uint32_t &expireTime = 60);

                /**
                 * @brief   析构函数
                 */
                virtual ~LoraStatus();

                /**
                 * @brief 读取LoraID
                 */
                uint16_t loraId() const;

                /**
                 * @brief 是否过期
                 */
                virtual bool timeIsExpired() const;

                /**
                 * @brief 获取的超出过期时间
                 */
                uint32_t getExpiredTime() const;

                /**
                 * @brief 获取预设的过期时限，以秒为单位
                 */
                uint32_t expireTime() const;

                /**
                 * @brief 调用此函数更新对象时间
                 */
                void updateTime(const chrono::steady_clock::time_point &updateTime = chrono::steady_clock::now());

                /**
                 * @brief 生成读取配置的协议流
                 */
                virtual int toBuffer(uint8_t *buffer, const int &size);

                /**
                 * @brief 判断设备参数是否正确
                 */
                bool configIsOk() const;

                /**
                 * @brief 更新Lora配置
                 */
                void updateConfig(const bool &ok = true);

                /**
                 * @brief 是否需要下载到采集器
                 */
                bool isMustDownload() const;

                /**
                 * @brief 需要下载
                 */
                void needToDownload(const bool &needed = true);

                /**
                 * @brief 获取当前系统时间
                 */
                static uint32_t now();

                /**
                 * @brief 获取当前时间
                 */
                static chrono::steady_clock::time_point steadyNow();
            };

            /**
             * @brief LORA状态管理器
             */
            class LoraStatusManager
            {
            public:
                LoraStatusManager();
                virtual ~LoraStatusManager();

                static LoraStatusManager *Instance();
                static void Add(const uint16_t &loraId, const uint32_t &expiredTime = 60);
                static bool ConfigIsOk(const uint16_t &loraId);
                virtual void add(const uint16_t &loraId, const uint32_t &expiredTime);
                virtual bool configIsOk(const uint16_t &loraId);

                static void UpdateTime(
                    const uint16_t &loraId,
                    const chrono::steady_clock::time_point &updateTime_ = chrono::steady_clock::now());

                virtual void updateTime(
                    const uint16_t &loraId,
                    const chrono::steady_clock::time_point &updateTime_ = chrono::steady_clock::now());

                static void UpdateConfig(const uint16_t& loraId, const bool &ok = true);
                virtual void updateConfig(const uint16_t& loraId, const bool &ok = true);

                virtual int toBuffer(uint8_t * buffer, const int& size);
                static int ToBuffer(uint8_t * buffer, const int& size);

                static void MustDownLoadConfig(const uint16_t& loraId, const bool& needed = false);
                virtual void mustDownLoadConfig(const uint16_t& loarId, const bool& needed = false);
            protected:
                virtual void initialize();

            private:
                static LoraStatusManager *globalInstance;

                /**
                 * @brief 存储Lora状态的向量
                 */
                vector<LoraStatus *> _status;

                /**
                 * @brief 状态与LoraID的映射表
                 */
                map<uint16_t, shared_ptr<LoraStatus>> _statusMap;
            };

            /**
             * @brief 数据序列号管理
             */
            class SerialNumberManager
            {
            public:
                SerialNumberManager();
                virtual ~SerialNumberManager();

                SerialNumber *getObject(const uint16_t &loraId, const uint8_t &nozzle);

                bool updateTransSerialNumber(const uint16_t &loraId, const uint8_t &nozzle, const uint16_t &sn);

                bool updateTaxSerialNumber(const uint16_t &loraId, const uint8_t &nozzle, const uint16_t &sn);

                void print();

                static SerialNumberManager *Instance();

            private:
                /**
                 * @brief
                 */
                map<uint32_t, shared_ptr<SerialNumber>> _dataMap;

                /**
                 * @brief 全局变量
                 */
                static SerialNumberManager *globalInstance;

            protected:
                /**
                 * 计算Hash值
                 */
                virtual uint32_t hashKey(const uint16_t &first, const uint8_t &second);

                /**
                 * @brief 初始化对象
                 */

                virtual void initialize();
            };

            /**
             * @brief Lora令牌协议管理类
             */
            class LoraTokenManager
            {
            public:
                LoraTokenManager();
                virtual ~LoraTokenManager();

                virtual int toBuffer(uint8_t *buffer, const int &size);

            private:
                /**
                 * @brief 设备序号
                 */
                int _currentTokenIndex{0};

                uint64_t _lastTime;
            };

            class LoraService : public BaseService,
                                public Publisher
            {
            public:
                LoraService(const string &serviceName);
                virtual ~LoraService();

                virtual void init() override;
                virtual void start() override;
                virtual void stop() override;

            protected:
                shared_ptr<LoraStatusManager> _loraStatus;

                /**
                 * @brief 数据流水号
                 */
                shared_ptr<SerialNumberManager> _snManger;

                /**
                 * @brief Lora流水号
                 */
                shared_ptr<LoraTokenManager> _loraTokens;

                /**
                 * @brief 用于处理Lora令牌
                 */
                virtual void dealLoraToken();

                /**
                 * @brief 用于处理Lora数据
                 */
                virtual bool dealLoraData();

                /**
                 * @brief 接收来自Lora的数据并处理
                 */
                void recvData();

                /**
                 * @brief 通过Lora向采集器发送数据
                 */
                void sendData();

                /**
                 * @brief 配置更新
                 */
                virtual int updateLora();

                /**
                 * @brief 管理Lora令牌协议
                 */
                virtual void sendLoraToken();

            private:
                // thread _thread;

                /**
                 * @brief 连接Lora的串口对象
                 */
                shared_ptr<SerialPort> _loraDevice;

                /**
                 * @brief 互斥锁
                 */
                mutex _mutex;

                /**
                 * 条件变量
                 */
                condition_variable _cv;

                /**
                 * 用于记录串口操作的时间
                 */
                chrono::time_point<chrono::steady_clock> _lastTime;

                /**
                 * @brief 等待回复
                 */
                volatile bool _waitingForAnswer{false};
            };
        }
    }
}

#endif